import { Forbbidend, NotFound, ParameterException, Success } from "../../code/http-exception"
import { generateToken } from "../../code/util"
import auth from "../../middlewares/auth";
import User from "../../sql/module/user/user";
import { TokenValidator, SubMenusValidator } from "../../validators/user";
import { logtype } from "../../lib/enum";
import Menu from "../../sql/module/menu";
import Role from "../../sql/module/user/role";
import { Op } from "sequelize";
import { InfoValidator, ListValidator } from "../../validators/public";
import { MenusValidator } from "../../validators/role_menu";

const router: Api = new Map()

async function emaillogin(accout: string, secret: string) {
    const user = await User.verifyEmailPassword(accout, secret)
    const token = generateToken(user.nickname)
    user.update({
        token
    })
    return token
}

router.set(['/login', 'post'], async (ctx, next) => {
    const v = await new TokenValidator().validate(ctx)
    const type = logtype.get(v.get('body.type'))
    let token;
    switch (type) {
        case 'USER_MINI_PROGRAM':
            throw new ParameterException('暂时没有对应处理函数')
            break;
        case 'USER_EMAIL':
            token = await emaillogin(v.get('body.phone'), v.get('body.password'))
            break;
        case 'USER_MOBILE':
            throw new ParameterException('暂时没有对应处理函数')
            break;
        default:
            throw new ParameterException('没有对应处理函数')
    }
    throw new Success(token, 20000)
})

router.set('/menus', [auth('public'), async (ctx, next) => {
    const isPhone = ctx.request.query.type || 0
    const uids = ctx.auth.uids
    const roleWhere: any = { state: 1, isPhone }
    if (!uids.includes(100)) {
        roleWhere[Op.or] = {
            ['$Roles.uid$']: uids,
            public: 1
        }
    }
    const menus: any[] = []
    const fun: (sub: any[], upLevel: string | null) => any = async (sub, upLevel) => {
        const menus = await Menu.findAll({
            attributes: ['label', 'url', 'type', 'img'],
            where: { upLevel, ...roleWhere },
            include: {
                attributes: [],
                model: Role
            }
        })
        await Promise.all(menus.map(async item => {
            const it = { ...item.dataValues }
            sub.push(it)
            it.sub = []
            return fun(it.sub, item.dataValues.url)
        }))
    }
    await fun(menus, null)
    throw new Success(menus)
}])

router.set('/relationship', [auth('public'), async (ctx, next) => {
    const v = await new SubMenusValidator().validate(ctx)
    const upLevel = v.get('body.upLevel').replace('/', '')
    const uids = ctx.auth.uids
    const where: any = { upLevel, state: 1 }
    let asideActive: string = ''
    let headActive: string = ''
    let menu: Menu | undefined = undefined
    let once = false
    let frist = true
    const menuOwm = await Menu.count({
        where: { url: upLevel, state: 1 },
    })
    if (!menuOwm) throw new Forbbidend('页面不存在', 10026)
    if (!uids.includes(100)) {
        const menuOwm = await Menu.count({
            where: { url: upLevel, [Op.or]: { '$Roles.uid$': uids, public: 1 }, state: 1 },
            include: { model: Role, attributes: [] }
        })
        where[Op.or] = { '$Roles.uid$': uids, public: 1 }
        if (!menuOwm) throw new Forbbidend('权限不足', 10026)
    }
    const menus = await Menu.findAll({
        attributes: ['label', 'url', 'type', 'img'],
        where,
        include: { model: Role, attributes: [] }
    })
    const fun: (bread: string[], url: string) => any = async (bread, url) => {
        if (!url) return
        const _menu = await Menu.findOne({ attributes: ['url', 'label', 'type', 'upLevel'], where: { url, state: 1 } })
        if (!_menu) return
        const data = _menu.dataValues
        bread.unshift(data)
        if (frist) {
            menu = data
            frist = false
        }
        if (data.type === 2 && !once) {
            asideActive = data.url
            once = true
        }
        if (data.upLevel === null) {
            headActive = data.url
            return bread
        }
        return await fun(bread, data.upLevel)
    }
    const bread = await fun([], upLevel)
    throw new Success({ menus, bread, asideActive, headActive, menu })
}])

//菜单列表
router.set('/menuList', [auth('menu'), async (ctx, next) => {
    const v = await new ListValidator().validate(ctx)
    const search_key: any = {}
    const limit = v.get('query.limit')
    const page_index = v.get('query.page_index')
    const isPhone = v.get('body.isPhone')
    const state = v.get('body.state')
    const label = v.get('body.label')
    isPhone && (search_key.isPhone = isPhone * 1)
    state && (search_key.state = state * 1)
    label && (search_key.label = {
        [Op.substring]: label
    })
    const total = await Menu.count({
        where: search_key,
    })
    const list = await Menu.findAll({
        attributes: { exclude: ['createdAt', 'updatedAt'] },
        where: search_key,
        limit: limit * 1,
        offset: (page_index - 1) * limit
    })
    throw new Success({ list, total }, 20000)
}])
//修改菜单（名称，移动端图标，pc端图标）
router.set('/updateMenu', [auth('editMenu'), async (ctx, next) => {
    const v = await new MenusValidator().validate(ctx)
    const id = v.get('query.id')
    const label = v.get('body.label')
    const img = v.get('body.img')
    const icon = v.get('body.icon')
    const menu = await Menu.findOne({
        where: {
            id
        }
    })
    if (!menu) { throw new NotFound() }
    await menu.update({
        label, img, icon
    })
    throw new Success()
}])
//菜单详情
router.set('/getMenu', [auth('editMenu'), async (ctx, next) => {
    const v = await new InfoValidator().validate(ctx)
    const id = v.get('query.id')
    const menu = await Menu.findOne({
        where: {
            id
        }
    })
    throw new Success(menu)
}])
//菜单启用禁用
router.set('/changeMenuState', [auth('menuState'), async (ctx, next) => {
    const v = await new InfoValidator().validate(ctx)
    const id = v.get('query.id')
    const state = v.get('query.state')
    const unChange = ["menu", "menuState", "User", "power"]
    const menu = await Menu.findOne({
        where: {
            id
        }
    })
    if (!menu) { throw new NotFound() }
    if (unChange.includes(menu.url || '')) {
        throw new Forbbidend("不可操作")
    }
    await menu.update({
        state
    })
    throw new Success()
}])
export { router }